﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Newtonsoft.Json;
using System.Data.SqlClient;
using System.Data;
using System.Configuration;
using NotificationLib;
using Accord.Statistics.Testing;
using System.Threading.Tasks;
using System.Reflection;
using GalacticLib;
using System.Text.RegularExpressions;


namespace Galactic
{
    public partial class WebService : System.Web.UI.Page
    {
        private DataTable GetDataTable(SqlCommand cmd)
        {

            cmd.Connection.Open();
            SqlDataAdapter adapter = new SqlDataAdapter();
            //DataSet ds = new DataSet();
            adapter.SelectCommand = cmd;
            DataTable dt = new DataTable();
            adapter.Fill(dt);
            return dt;

        }

        private DataSet GetDataSet(SqlCommand cmd)
        {
            cmd.Connection.Open();
            SqlDataAdapter adapter = new SqlDataAdapter();
            DataSet ds = new DataSet();
            adapter.SelectCommand = cmd;           
            adapter.Fill(ds);
            return ds;
        }

        private void OutputJson(string s)
        {
            Response.ContentType = "text/json";
            Response.Write(s);
        }

        private SqlCommand GetCommandForSproc(SqlConnection conn, string keyName = "sproc")
        {
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = conn;
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            cmd.CommandText = Request[keyName];

            foreach (string key in Request.Form.Keys)
            {
                if (key == keyName)
                    continue;

               string val = Uri.UnescapeDataString(Request[key]);

                SqlParameter p = new SqlParameter(key, val);
                cmd.Parameters.Add(p);
            }


            cmd.CommandTimeout = 1000 * 60; 
            return cmd;
        }

        private SqlCommand GetCommandByParameter(SqlConnection conn, string commandText, object a)
        {
             var type = a.GetType();
            List<PropertyInfo> props = type.GetProperties().ToList();
             

            SqlCommand cmd = new SqlCommand();
            cmd.Connection = conn;
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            cmd.CommandText = commandText;

            foreach ( PropertyInfo pInfo in props)
            {

                string key = pInfo.Name;
                object v = pInfo.GetValue(a, null);

                SqlParameter p = new SqlParameter(key, v);
                cmd.Parameters.Add(p);
            }
            
            cmd.CommandTimeout = 1000 * 60;
            return cmd;
        }

        List<DataSetData> GetDataSetData(int dataSetId)
        {

            using (SqlConnection conn = new SqlConnection(Application["ConnectionString"].ToString()))
            {
                SqlCommand cmd = GetCommandByParameter(conn, "usp_GetDatasetData",
                                                new
                                                {
                                                    id = dataSetId
                                                });

                DataTable dt = GetDataTable(cmd);
                string s = JsonConvert.SerializeObject(dt, Formatting.Indented);
                return JsonConvert.DeserializeObject<List<DataSetData>>(s);
            }
        }


        protected void Page_Load(object sender, EventArgs e)
        {

            if(Request.Form.AllKeys.Contains("sproc"))
            {

                switch (Request["sproc"].ToLower())
                {


                    case "testfilter":
                        {
                            int dataSetid = int.Parse(Request["DataSetId"]);

                            List<DataSetData> Data = GetDataSetData(dataSetid);

                            string morphologyRegex = Uri.UnescapeDataString(Request["MorphologyRegex"]);
                            
                            int limit = int.Parse(Request["limit"]);

                            List<DataSetData> subset = Data.Where(g => Regex.IsMatch(g.Morphology, morphologyRegex)).ToList();

                            int matchCount = subset.Count;

                            subset = subset.Take(limit).ToList();

                            var temp = new List<object>();
                            temp.Add(subset);
                            temp.Add(matchCount);

                            string json = JsonConvert.SerializeObject(temp);
                            OutputJson(json);

                            break;
                        }

                    case "getpointwiseforchart":
                        {

                            int dataSetid = int.Parse(Request["DataSetId"]);

                            List<DataSetData> Data = GetDataSetData(dataSetid);

                            double fittingRange = double.Parse(Request["FittingRange"]);
                            string morphologyRegex = Uri.UnescapeDataString(Request["SecondaryRegex"]);
                            long galaxyId = long.Parse(Request["startobject"]);

                            DataRunRequest req = new DataRunRequest();
                            req.FittingRange = fittingRange;
                            req.SecondaryRegex = morphologyRegex;

                            req.Is3D = bool.Parse(Request["Is3D"]);
                            
                            DataSetData primary = Data.First(p => p.id == galaxyId);

                            List<DataSetData> secondaries = DataRunProcessor.GetSecondaries(primary, Data, req);

                            List<DataSetData> orderedSecondaries = DataRunProcessor.OrderAndCalculatePDLogs(primary, secondaries, req);

                            var temp = new List<object>();
                            temp.Add(orderedSecondaries);
                            temp.Add( DataRunProcessor.GetPointwiseDimension(primary, orderedSecondaries, req));

                            string json = JsonConvert.SerializeObject(temp);
                            OutputJson(json);

                            break;
                        }

                    case "getnearbyobjectsandprimary":
                    {
                         using(SqlConnection conn = new SqlConnection(Application["ConnectionString"].ToString()))
                                    {

                                        int dataSetid = int.Parse(Request["DataSetId"]);

                                        List<DataSetData> Data = GetDataSetData(dataSetid);

                                         double fittingRange = double.Parse(Request["FittingRange"]);
                                         string morphologyRegex = "";// Request["SecondaryRegex"];
                                         long galaxyId = long.Parse(Request["startobject"]);
                                        
                                         DataRunRequest req = new DataRunRequest();
                                         req.FittingRange = fittingRange;
                                         req.SecondaryRegex = morphologyRegex;
                                         req.Is3D = bool.Parse(Request["Is3D"]);

                                         DataSetData primary = Data.First(p => p.id == galaxyId);

                                         List<DataSetData> secondaries = DataRunProcessor.GetSecondaries(primary, Data, req);
                                         List<DataSetData> orderedSecondaries = secondaries.OrderBy(sec => sec.PD_DistanceRad).ToList();

                                         orderedSecondaries.Add(primary);


                                         OutputJson(JsonConvert.SerializeObject(orderedSecondaries));
                         }
                        break;
                    }


                    case "savepdrun":
                        {
                            string json = Request["results"];
                            List<PDValue> PDValues = JsonConvert.DeserializeObject<List<PDValue>>(json);
                            ///data run id for marking run as saved
                            long DataRunRequestId = PDValues.First().DataRunRequestId;
                            PDValues.ForEach(PDv =>
                                {
                                    using(SqlConnection conn = new SqlConnection(Application["ConnectionString"].ToString()))
                                    {
                                        SqlCommand cmd = new SqlCommand("usp_SavePDValue", conn);
                                        cmd.CommandType = CommandType.StoredProcedure;
                            
                                        cmd.Parameters.Add( new SqlParameter("PD", PDv.PD));
                                        cmd.Parameters.Add( new SqlParameter("DataId", PDv.DataId));
                                        cmd.Parameters.Add( new SqlParameter("DataRunRequestId", PDv.DataRunRequestId));
                                        cmd.Parameters.Add(new SqlParameter("SecondaryCount", PDv.SecondaryCount));
                                        cmd.Connection.Open();
                                        cmd.ExecuteNonQuery();
                                        

                                    }
                                });

                            /*
                            using (SqlConnection conn = new SqlConnection(Application["ConnectionString"].ToString()))
                            {
                                SqlCommand cmd = new SqlCommand("usp_FinishedDataRun", conn);
                                cmd.CommandType = CommandType.StoredProcedure;

                                cmd.Parameters.Add(new SqlParameter("DataRunRequestId", DataRunRequestId));
                       
                                cmd.Connection.Open();
                                cmd.ExecuteNonQuery();


                            }
                            */

                            Response.Write("OK");

                            break;
                        }

                    default:
                        {
                            using (SqlConnection conn = new SqlConnection(Application["ConnectionString"].ToString()))
                            {
                                SqlCommand cmd = GetCommandForSproc(conn);
                                DataTable dt = GetDataTable(cmd);
                                string s = JsonConvert.SerializeObject(dt, Formatting.Indented);

                                OutputJson(s);
                            }
                            break;
                        }
                }
            }
            if (Request.Form.AllKeys.Contains("multiresultsproc"))
            {
                using (SqlConnection conn = new SqlConnection(Application["ConnectionString"].ToString()))
                {

                    SqlCommand cmd = GetCommandForSproc(conn,"multiresultsproc");

                    DataSet dt = GetDataSet(cmd);
                    string s = JsonConvert.SerializeObject(dt, Formatting.Indented);

                    OutputJson(s);
                }
            }
            else
            {
                if(Request.Form.AllKeys.Contains("method"))
                {
                     using (SqlConnection conn = new SqlConnection(Application["ConnectionString"].ToString()))
                    {
                        string output = "";

                        switch (Request["method"].ToUpper())
                        {
                               

                            case "KSTEST":
                                {

                                    SqlCommand cmd = new SqlCommand();
                                    cmd.Connection = conn;
                                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                                    cmd.CommandText = "usp_GetDataForKsTest";

                                //   cmd.Parameters.Add(new SqlParameter("DataRun1", "3"));
                                //   cmd.Parameters.Add(new SqlParameter("DataRun2", "3"));

                                  cmd.Parameters.Add(new SqlParameter("DataRun1", Request.Form["DataRun1"].ToString()));
                                   cmd.Parameters.Add(new SqlParameter("DataRun2", Request.Form["DataRun2"].ToString()));
                                  
                                    DataSet ds = GetDataSet(cmd);

                                    List<List<double>> data = new List<List<double>>(2);
                                    
                                    //there will be exactly two tables in result set when passed two valid DataRun ids.
                                    foreach(DataTable t in ds.Tables)
                                    {
                                        List<double> set = new List<double>(t.Rows.Count);
                                        data.Add(set);
                                        foreach(DataRow r in t.Rows)
                                        {
                                            double d = double.Parse(r["d"].ToString());
                                            set.Add(d);
                                        }
                                    }

                                    double[] setArray1 = data[0].ToArray();
                                    double[] setArray2 = data[1].ToArray();                                    

                                    var ks = new TwoSampleKolmogorovSmirnovTest(setArray1, setArray2);

                                //    Console.WriteLine("KS-Test");
                                 //   Console.WriteLine("Test p-value: " + ks.PValue);
                                 //   Console.WriteLine("Significant? " + ks.Significant); 

                                    var res = 
                                    new {
                                       PValue = ks.PValue,
                                       Significant = ks.Significant
                                    };

                                    conn.Close();


                                    output = JsonConvert.SerializeObject(ks, Formatting.Indented);
                                    OutputJson(output);


                                    break;
                                }

                            case "UPLOADDATASET":
                                {

                                    SqlCommand cmd = new SqlCommand();
                                    cmd.Connection = conn;
                                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                                    cmd.CommandText = "usp_AddDataSet";

                                    HttpFileCollection files = Request.Files;
                                    HttpPostedFile file = files["datafile"]; 

                                    cmd.Parameters.Add(new SqlParameter("Name", Request.Form["DataSetName"].ToString()));
                                    cmd.Parameters.Add(new SqlParameter("FileName", Server.MapPath(@"temp\" + file.FileName)));

                                   
                                                                       
                                    file.SaveAs(Server.MapPath(@"temp\" + file.FileName));


                                    DataTable dt = GetDataTable(cmd);

                                    conn.Close();

                                    output = JsonConvert.SerializeObject(dt, Formatting.Indented);
                                    OutputJson(output);

                                    break;
                                }

                            case "PUSHOVERTEST":
                                {
                                    string userKey = "";

                                    SqlCommand cmd = new SqlCommand();
                                    cmd.Connection = conn;
                                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                                    cmd.CommandText = "usp_GetPushoverKey";
                                    
                                    cmd.Parameters.Add(new SqlParameter("Username", Request.Form["Username"].ToString()));
                                    
                                    cmd.Connection.Open();

                                    SqlDataReader reader = cmd.ExecuteReader();
                                    reader.Read();
                                    userKey = reader["PushoverKey"].ToString();
                                    reader.Close();
                                    conn.Close();
                                    

                                    PushoverNotificationConfig pnc = (PushoverNotificationConfig)Application["PushoverNotificationConfig"];
                                    PushoverNotification n = new PushoverNotification(pnc, userKey, Request.Form["PushoverTitle"], Request.Form["PushoverMessage"]);

                                    n.Send();

                                   string result = "Success";
                                    OutputJson(JsonConvert.SerializeObject(result));

                                  //  output = User.Identity.Name;

                                    break;
                                }
                            case "EMAILTEST":
                                {
                                    EmailNotificationConfig enc = (EmailNotificationConfig)Application["EmailNotificationConfig"];

                                    SqlCommand cmd = new SqlCommand();
                                    cmd.Connection = conn;
                                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                                    cmd.CommandText = "usp_GetUserEmail";

                                    cmd.Parameters.Add(new SqlParameter("Username", Request.Form["Username"].ToString()));

                                    cmd.Connection.Open();

                                    SqlDataReader reader = cmd.ExecuteReader();
                                    reader.Read();
                                    string to = reader["Email"].ToString();

                                    EmailNotification notif = new EmailNotification(enc, Request.Form["EmailSubject"], Request.Form["EmailMessage"], to);

                                    notif.Send();

                                    string result = "Succes";
                                    OutputJson(JsonConvert.SerializeObject(result));

                                    break;

                                }
                        }

                        //output = JsonConvert.SerializeObject(output, Formatting.Indented);
                       // OutputJson(output);
                
                
                    }
                }
            }
            
        }

     
    }
}